Skip to content

Update plugin ZTools 提供商 v1.0.1#305

Closed
kaineooo wants to merge 1 commit into
ZToolsCenter:mainfrom
kaineooo:plugin/f-provider
Closed

Update plugin ZTools 提供商 v1.0.1#305
kaineooo wants to merge 1 commit into
ZToolsCenter:mainfrom
kaineooo:plugin/f-provider

Conversation

@kaineooo

Copy link
Copy Markdown
Contributor

插件信息

  • 名称: ZTools 提供商
  • 插件ID: f-provider
  • 版本: 1.0.1
  • 描述: OCR + 翻译提供商集合(百度/谷歌/有道/微软翻译、微信 OCR)
  • 作者: kaineooo
  • 类型: 更新

本次变更

  • feat: ZTools OCR + 翻译提供商插件(截图识别 / 代码翻译 / manage)
  • chore: 调整插件命名空间
  • chore: 调整资源url
  • feat: 微信 OCR 原生模块支持 macOS(libwxocr.dylib)
  • feat: 截图识别结果改为独立窗口展示(左图右文 + 拖动缩放)

截图 / 演示

自检清单

  • plugin.json 的 name / title / version / description / author 字段均已检查
  • 已移除调试日志、未使用文件、敏感信息(.env、token、密钥等)
  • 本次 PR 的 diff 仅涉及 plugins/f-provider/ 目录
  • 已在本地 ZTools 客户端实际加载并测试过此插件,主要功能正常
  • 同意以仓库声明的开源协议发布此插件

此 PR 由 ztools-plugin-cli 自动管理:每次 ztools publish 在分支上追加一个 commit,PR 链接保持不变。

- feat: ZTools OCR + 翻译提供商插件(截图识别 / 代码翻译 / manage)
- chore: 调整插件命名空间
- chore: 调整资源url
- feat: 微信 OCR 原生模块支持 macOS(libwxocr.dylib)
- feat: 截图识别结果改为独立窗口展示(左图右文 + 拖动缩放)
@kaineooo kaineooo closed this Jul 10, 2026

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the screenshot OCR feature to display results in a new, dedicated borderless child window instead of the main window. The main window now coordinates the capture and recognition process, opens the child window, injects the results, and exits, while the child window handles interactive image viewing and text selection. The review comments provide valuable feedback to improve robustness, including resetting the UI state when a capture is canceled, adding defensive checks to prevent executing JavaScript on a destroyed window, handling potential promise rejections from clipboard operations, and ensuring the image scale factor remains positive on extreme window resizes.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines 73 to 82
if (!imgBase64) {
phase.value = 'idle'
errorToast('已取消截图')
// 取消后退出插件,回到宿主
try {
window.ztools.outPlugin()
} catch (_) {
/* ignore */
}
return
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

当用户取消截图时,phase.value 没有被重置为 'idle'。如果 window.ztools.outPlugin() 调用失败或未能成功关闭/隐藏插件窗口,UI 界面将会一直卡在 'capturing'(截图进行中)的状态。建议在退出前将 phase.value 重置为 'idle' 以保证状态机的健壮性。

    if (!imgBase64) {
      phase.value = 'idle'
      errorToast('已取消截图')
      // 取消后退出插件,回到宿主
      try {
        window.ztools.outPlugin()
      } catch (_) {
        /* ignore */
      }
      return
    }

Comment on lines +222 to 234
function injectData(
win: BrowserWindow.WindowInstance,
data: { image: string; lines: OcrLine[]; isDark: boolean; logo?: string }
): void {
try {
// 序列化为安全的 JSON,避免引号/换行破坏 JS 字符串
const payload = JSON.stringify(data)
const code = `window.__loadScreenOcrResult && window.__loadScreenOcrResult(${payload});`
win.webContents.executeJavaScript(code)
} catch (_) {
/* ignore:兜底注入会再试 */
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

在调用 win.webContents.executeJavaScript 之前,建议先检查窗口是否已被销毁(win.isDestroyed())。如果用户在 800ms 内快速关闭了结果窗口,延迟执行的 injectData 可能会尝试操作已销毁的窗口,从而引发异常。进行防御性检查可以提高代码的稳定性。

function injectData(
  win: BrowserWindow.WindowInstance,
  data: { image: string; lines: OcrLine[]; isDark: boolean; logo?: string }
): void {
  try {
    if (!win || win.isDestroyed()) return
    // 序列化为安全的 JSON,避免引号/换行破坏 JS 字符串
    const payload = JSON.stringify(data)
    const code = `window.__loadScreenOcrResult && window.__loadScreenOcrResult(${payload});`
    win.webContents?.executeJavaScript(code)
  } catch (_) {
    /* ignore:兜底注入会再试 */
  }
}

Comment on lines +74 to +84
function copyText(text: string) {
if (!text) return
try {
navigator.clipboard?.writeText(text)
} catch (_) {
/* 子窗口可能无 clipboard 权限,静默失败 */
}
copied.value = text
if (copiedTimer) window.clearTimeout(copiedTimer)
copiedTimer = window.setTimeout(() => (copied.value = ''), 1200)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

navigator.clipboard.writeText 返回的是一个 Promise。由于它是异步执行的,外部的 try-catch 块无法捕获其异步的 Promise Rejection(例如当文档未聚焦或权限被拒绝时,会抛出 DOMException: Document is not focused)。这会导致控制台出现未捕获的 Promise 拒绝错误。建议显式使用 .catch() 来处理,并先判断 navigator.clipboard 是否存在。

function copyText(text: string) {
  if (!text) return
  if (navigator.clipboard) {
    navigator.clipboard.writeText(text).catch(() => {
      /* 子窗口可能无 clipboard 权限,静默失败 */
    })
  }
  copied.value = text
  if (copiedTimer) window.clearTimeout(copiedTimer)
  copiedTimer = window.setTimeout(() => (copied.value = ''), 1200)
}

Comment on lines +119 to +128
function computeFitScale(): number {
const vp = viewportRef.value
const vw = vp ? vp.clientWidth : window.innerWidth
const vh = vp ? vp.clientHeight : window.innerHeight
if (!naturalWidth.value || !naturalHeight.value || !vw || !vh) return 1
// 留 16px 内边距
const aw = vw - 16
const ah = vh - 16
return Math.min(aw / naturalWidth.value, ah / naturalHeight.value, 1)
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

computeFitScale 中,如果用户将窗口缩放到极小(宽度或高度小于 16px),awah 可能会计算为负数,从而导致返回一个负的缩放比例(scale),这会引起图片渲染异常或翻转。建议使用 Math.max(1, ...) 确保可用宽高始终为正数。

function computeFitScale(): number {
  const vp = viewportRef.value
  const vw = vp ? vp.clientWidth : window.innerWidth
  const vh = vp ? vp.clientHeight : window.innerHeight
  if (!naturalWidth.value || !naturalHeight.value || !vw || !vh) return 1
  // 留 16px 内边距,确保不为负数
  const aw = Math.max(1, vw - 16)
  const ah = Math.max(1, vh - 16)
  return Math.min(aw / naturalWidth.value, ah / naturalHeight.value, 1)
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants